#ifndef PAGE_H
#define PAGE_H
#include <multiboot.h>
#include <cpu.h>

// Page definitions

#define PAGE_SIZE_4M (4096*1024)
#define PAGE_SIZE_4K (4096)

// PTE / PDE entries

#define PAGE_PRESENT 	0x1
#define PAGE_NOTPRESENT 0x0
#define PAGE_RW		0x2
#define PAGE_RO		0x0
#define PAGE_USER	0x4
#define PAGE_SUPERVISOR	0x0
#define PAGE_DIRTY	0x40
#define PAGE_CLEAN	0x00
#define PAGE_ACCESSED	0x20
#define PAGE_UNUSED	0x00
#define PAGE_4M		0x80
#define PAGE_4K		0x00

#define PAGE_FLAGS_4M 		(PAGE_4M | PAGE_RW | PAGE_PRESENT)
#define PAGE_FLAGS_4M_USER 	(PAGE_FLAGS_4M | PAGE_USER)

#define PAGE_FLAGS_4K 		(PAGE_RW | PAGE_PRESENT)
#define PAGE_FLAGS_4K_USER 	(PAGE_FLAGS_4K | PAGE_USER)


extern void *kern_start; // <-- start of kernel space
extern void *kern_end; // <-- end of kernel space


typedef unsigned int page_t;

typedef struct TAGpage_4m_t {
   unsigned int table  : 10;
   unsigned int offset : 22;
} __attribute__((packed)) page_4m_t;

typedef struct TAGpage_4k_t {
   unsigned int dir    : 10;
   unsigned int table  : 10;
   unsigned int offset : 12;
} __attribute__((packed)) page_4k_t;

#define MASK_4K(size)   	((unsigned int)(size) & ~0xFFF)
#define MASK_4M(size) 		((unsigned int)(size) & ~0x1FFFFF)

#define MASK_4K_LOW(size)   	((unsigned int)(size) & 0xFFF)
#define MASK_4M_LOW(size) 	((unsigned int)(size) & 0x1FFFFF)

#define ALIGN_4K		(((unsigned int)(size) + 0x1000) & ~0xFFF)
#define ALIGN_4M(size) 		(((unsigned int)(size) + 0x400000) & ~0x1FFFFF)

extern void setup_page_stacks (multiboot_info_t *);

extern page_t pop_page();
extern void push_page(page_t );

extern void map_page(page_t, unsigned int);
extern void unmap_page(page_t);

extern void handle_page_fault(struct regs *);
extern void setup_mm(multiboot_info_t *);

/// XXXXXX
extern void *kmalloc_stupid(int);

#endif
